home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / Properties.java < prev    next >
Text File  |  1998-09-22  |  11KB  |  383 lines

  1. /*
  2.  * @(#)Properties.java    1.31 98/07/01
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  * 
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.util;
  16.  
  17. import java.io.IOException;
  18. import java.io.PrintStream;
  19. import java.io.PrintWriter;
  20. import java.io.InputStream;
  21. import java.io.OutputStream;
  22. import java.util.Hashtable;
  23.  
  24. /**
  25.  * The <code>Properties</code> class represents a persistent set of 
  26.  * properties. The <code>Properties</code> can be saved to a stream 
  27.  * or loaded from a stream. Each key and its corresponding value in 
  28.  * the property list is a string. 
  29.  * <p>
  30.  * A property list can contain another property list as its 
  31.  * "defaults"; this second property list is searched if 
  32.  * the property key is not found in the original property list. 
  33.  *
  34.  * @author  Arthur van Hoff
  35.  * @version 1.31, 07/01/98
  36.  * @since   JDK1.0
  37.  */
  38. public
  39. class Properties extends Hashtable {
  40.     /**
  41.      * A property list that contains default values for any keys not 
  42.      * found in this property list. 
  43.      *
  44.      * @since   JDK1.0
  45.      */
  46.     protected Properties defaults;
  47.  
  48.     /**
  49.      * Creates an empty property list with no default values. 
  50.      *
  51.      * @since   JDK1.0
  52.      */
  53.     public Properties() {
  54.     this(null);
  55.     }
  56.  
  57.     /**
  58.      * Creates an empty property list with the specified defaults. 
  59.      *
  60.      * @param   defaults   the defaults.
  61.      * @since   JDK1.0
  62.      */
  63.     public Properties(Properties defaults) {
  64.     this.defaults = defaults;
  65.     }
  66.  
  67.     /**
  68.      * Reads a property list from an input stream. 
  69.      *
  70.      * @param      in   the input stream.
  71.      * @exception  IOException  if an error occurred when reading from the
  72.      *               input stream.
  73.      * @since   JDK1.0
  74.      */
  75.     public synchronized void load(InputStream in) throws IOException {
  76.     /**
  77.      * Use char array to collect the key and val chars.  Use an initial
  78.      * size of 80 chars and double the array during expansion.  
  79.      */
  80.     int buflen = 80;
  81.     char[] buf = new char[buflen];
  82.     int bufindx = 0;
  83.     
  84.     in = Runtime.getRuntime().getLocalizedInputStream(in);
  85.  
  86.     int ch = in.read();
  87.     while (true) {
  88.         switch (ch) {
  89.           case -1:
  90.         return;
  91.  
  92.           case '#':
  93.           case '!':
  94.         do {
  95.             ch = in.read();
  96.         } while ((ch >= 0) && (ch != '\n') && (ch != '\r'));
  97.         continue;
  98.  
  99.           case '\n':
  100.           case '\r':
  101.           case ' ':
  102.           case '\t':
  103.         ch = in.read();
  104.         continue;
  105.         }
  106.  
  107.         /* Read the key into buf */
  108.         bufindx = 0;
  109.         while ((ch >= 0) && (ch != '=') && (ch != ':') && 
  110.            (ch != ' ') && (ch != '\t') && (ch != '\n') && (ch != '\r')) {
  111.         /* append ch to buf */
  112.         if (bufindx >= buflen) {
  113.             /* expand buf */
  114.             buflen *= 2;
  115.             char[] nbuf = new char[buflen];
  116.             System.arraycopy(buf, 0, nbuf, 0, buf.length);
  117.             buf = nbuf;
  118.         }
  119.         buf[bufindx++] = (char)ch;
  120.         ch = in.read();
  121.         }
  122.         while ((ch == ' ') || (ch == '\t')) {
  123.         ch = in.read();
  124.         }
  125.         if ((ch == '=') || (ch == ':')) {
  126.         ch = in.read();
  127.         }
  128.         while ((ch == ' ') || (ch == '\t')) {
  129.         ch = in.read();
  130.         }
  131.         /* create the key */
  132.         String key = new String(buf, 0, bufindx);
  133.  
  134.         /* Read the value into buf, reuse buf */
  135.         bufindx = 0;
  136.         while ((ch >= 0) && (ch != '\n') && (ch != '\r')) {
  137.         int next = 0;
  138.         if (ch == '\\') {
  139.             switch (ch = in.read()) {
  140.               case '\r':
  141.             if (((ch = in.read()) == '\n') ||
  142.                 (ch == ' ') || (ch == '\t')) {
  143.               // fall thru to '\n' case
  144.             } else continue;
  145.               case '\n': 
  146.             while (((ch = in.read()) == ' ') || (ch == '\t'));
  147.             continue;
  148.               case 't': ch = '\t'; next = in.read(); break;
  149.               case 'n': ch = '\n'; next = in.read(); break;
  150.               case 'r': ch = '\r'; next = in.read(); break;
  151.               case 'u': {
  152.             while ((ch = in.read()) == 'u');
  153.             int d = 0;
  154.               loop:
  155.             for (int i = 0 ; i < 4 ; i++) {
  156.                 next = in.read();
  157.                 switch (ch) {
  158.                   case '0': case '1': case '2': case '3': case '4':
  159.                   case '5': case '6': case '7': case '8': case '9':
  160.                 d = (d << 4) + ch - '0';
  161.                 break;
  162.                   case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  163.                 d = (d << 4) + 10 + ch - 'a';
  164.                 break;
  165.                   case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  166.                 d = (d << 4) + 10 + ch - 'A';
  167.                 break;
  168.                   default:
  169.                 break loop;
  170.                 }    
  171.                 ch = next;
  172.             }
  173.             ch = d;
  174.             break;
  175.               }
  176.               default: next = in.read(); break;
  177.             }
  178.         } else {
  179.             next = in.read();
  180.         }
  181.         /* append ch to buf */
  182.         if (bufindx >= buflen) {
  183.             /* expand buf */
  184.             buflen *= 2;
  185.             char[] nbuf = new char[buflen];
  186.             System.arraycopy(buf, 0, nbuf, 0, buf.length);
  187.             buf = nbuf;
  188.         }
  189.         buf[bufindx++] = (char)ch;
  190.         ch = next;
  191.         }
  192.         /* create the val */
  193.         String val = new String(buf, 0, bufindx);
  194.  
  195.         put(key, val);
  196.     }
  197.     }
  198.  
  199.     /**
  200.      * Stores this property list to the specified output stream. The 
  201.      * string header is printed as a comment at the beginning of the stream.
  202.      *
  203.      * @param   out      an output stream.
  204.      * @param   header   a description of the property list.
  205.      * @since   JDK1.0
  206.      */
  207.     public synchronized void save(OutputStream out, String header) {
  208.     OutputStream localOut = Runtime.getRuntime().getLocalizedOutputStream(out);
  209.     PrintStream prnt = new PrintStream(localOut, false);
  210.     boolean localize = localOut != out;
  211.  
  212.     if (header != null) {
  213.         prnt.write('#');
  214.         prnt.println(header);
  215.     }
  216.     prnt.write('#');
  217.     prnt.println(new Date());
  218.  
  219.     for (Enumeration e = keys() ; e.hasMoreElements() ;) {
  220.         String key = (String)e.nextElement();
  221.         prnt.print(key);
  222.         prnt.write('=');
  223.  
  224.         String val = (String)get(key);
  225.         int len = val.length();
  226.         boolean empty = false;
  227.  
  228.         for (int i = 0 ; i < len ; i++) {
  229.         int ch = val.charAt(i);
  230.  
  231.         switch (ch) {
  232.           case '\\': prnt.write('\\'); prnt.write('\\'); break;
  233.           case '\t': prnt.write('\\'); prnt.write('t'); break;
  234.           case '\n': prnt.write('\\'); prnt.write('n'); break;
  235.           case '\r': prnt.write('\\'); prnt.write('r'); break;
  236.  
  237.           default:
  238.             if ((ch < ' ') || (ch >= 127) || (empty && (ch == ' '))) {
  239.             if ((ch > 255) && localize) {
  240.                 prnt.write(ch);
  241.             } else {
  242.                 prnt.write('\\');
  243.                 prnt.write('u');
  244.                 prnt.write(toHex((ch >> 12) & 0xF));
  245.                 prnt.write(toHex((ch >>  8) & 0xF));
  246.                 prnt.write(toHex((ch >>  4) & 0xF));
  247.                 prnt.write(toHex((ch >>  0) & 0xF));
  248.             }
  249.             } else {
  250.             prnt.write(ch);
  251.             }
  252.         }
  253.         empty = false;
  254.         }
  255.         prnt.write('\n');
  256.     }
  257.     }
  258.  
  259.     /**
  260.      * Searches for the property with the specified key in this property list.
  261.      * If the key is not found in this property list, the default property list,
  262.      * and its defaults, recursively, are then checked. The method returns
  263.      * <code>null</code> if the property is not found.
  264.      *
  265.      * @param   key   the property key.
  266.      * @return  the value in this property list with the specified key value.
  267.      * @see     java.util.Properties#defaults
  268.      * @since   JDK1.0
  269.      */
  270.     public String getProperty(String key) {
  271.     String val = (String)super.get(key);
  272.     return ((val == null) && (defaults != null)) ? defaults.getProperty(key) : val;
  273.     }
  274.  
  275.     /**
  276.      * Searches for the property with the specified key in this property list.
  277.      * If the key is not found in this property list, the default property list,
  278.      * and its defaults, recursively, are then checked. The method returns the
  279.      * default value argument if the property is not found.
  280.      *
  281.      * @param   key            the hashtable key.
  282.      * @param   defaultValue   a default value.
  283.      *
  284.      * @return  the value in this property list with the specified key value.
  285.      * @see     java.util.Properties#defaults
  286.      * @since   JDK1.0
  287.      */
  288.     public String getProperty(String key, String defaultValue) {
  289.     String val = getProperty(key);
  290.     return (val == null) ? defaultValue : val;
  291.     }
  292.  
  293.     /**
  294.      * Returns an enumeration of all the keys in this property list, including
  295.      * the keys in the default property list.
  296.      *
  297.      * @return  an enumeration of all the keys in this property list, including
  298.      *          the keys in the default property list.
  299.      * @see     java.util.Enumeration
  300.      * @see     java.util.Properties#defaults
  301.      * @since   JDK1.0
  302.      */
  303.     public Enumeration propertyNames() {
  304.     Hashtable h = new Hashtable();
  305.     enumerate(h);
  306.     return h.keys();
  307.     }
  308.  
  309.     /**
  310.      * Prints this property list out to the specified output stream. 
  311.      * This method is useful for debugging. 
  312.      *
  313.      * @param   out   an output stream.
  314.      * @since   JDK1.0
  315.      */
  316.     public void list(PrintStream out) {
  317.     out.println("-- listing properties --");
  318.     Hashtable h = new Hashtable();
  319.     enumerate(h);
  320.     for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
  321.         String key = (String)e.nextElement();
  322.         String val = (String)h.get(key);
  323.         if (val.length() > 40) {
  324.         val = val.substring(0, 37) + "...";
  325.         }
  326.         out.println(key + "=" + val);
  327.     }
  328.     }
  329.  
  330.     /**
  331.      * Prints this property list out to the specified output stream. 
  332.      * This method is useful for debugging. 
  333.      *
  334.      * @param   out   an output stream.
  335.      * @since   JDK1.1
  336.      */
  337.     /*
  338.      * Rather than use an anonymous inner class to share common code, this
  339.      * method is duplicated in order to ensure that a non-1.1 compiler can
  340.      * compile this file.
  341.      */
  342.     public void list(PrintWriter out) {
  343.     out.println("-- listing properties --");
  344.     Hashtable h = new Hashtable();
  345.     enumerate(h);
  346.     for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
  347.         String key = (String)e.nextElement();
  348.         String val = (String)h.get(key);
  349.         if (val.length() > 40) {
  350.         val = val.substring(0, 37) + "...";
  351.         }
  352.         out.println(key + "=" + val);
  353.     }
  354.     }
  355.  
  356.     /**
  357.      * Enumerates all key/value pairs in the specified hastable.
  358.      * @param h the hashtable
  359.      */
  360.     private synchronized void enumerate(Hashtable h) {
  361.     if (defaults != null) {
  362.         defaults.enumerate(h);
  363.     }
  364.     for (Enumeration e = keys() ; e.hasMoreElements() ;) {
  365.         String key = (String)e.nextElement();
  366.         h.put(key, get(key));
  367.     }
  368.     }
  369.  
  370.     /**
  371.      * Convert a nibble to a hex character
  372.      * @param    nibble    the nibble to convert.
  373.      */
  374.     private static char toHex(int nibble) {
  375.     return hexDigit[(nibble & 0xF)];
  376.     }
  377.  
  378.     /** A table of hex digits */
  379.     private static char[] hexDigit = {
  380.     '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
  381.     };
  382. }
  383.